package ru.gerunn.silent.client;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import org.apache.log4j.Logger;

import ru.gerunn.silent.callable.RW;
import ru.gerunn.silent.exception.SilentClientException;
import ru.gerunn.silent.exception.SilentReaderException;
import ru.gerunn.silent.exception.SilentWriterException;
import ru.gerunn.silent.io.ConsoleReader;
import ru.gerunn.silent.io.ConsoleWriter;
import ru.gerunn.silent.io.Reader;
import ru.gerunn.silent.io.SocketReader;
import ru.gerunn.silent.io.SocketWriter;
import ru.gerunn.silent.io.Writer;

public class Client {

	public static Logger log = Logger.getLogger(Client.class);

	private final int port;
	private final SSLSocket socket;

	public Client() throws SilentClientException {
		this(8883);
	}

	public Client(int port) throws SilentClientException {
		log.info("client creation start");
		this.port = port;
		SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
		SSLSocket socket = null;
		try {
			socket = (SSLSocket) socketFactory.createSocket("localhost", this.port);
		} catch (UnknownHostException e) {
			throw new SilentClientException("UnknownHostException while creating socket", e);
		} catch (IOException e) {
			throw new SilentClientException("IOException while creating socket", e);
		}

		try {
			socket.startHandshake();
		} catch (IOException e) {
			throw new SilentClientException("IOException while handshake", e);
		}
		this.socket = socket;
		log.info("client creation finish");
	}

	public void start() throws SilentReaderException, SilentWriterException, SilentClientException {
		log.info("client starting start");
		Writer consoleWriter = new ConsoleWriter();
		Writer socketWriter = new SocketWriter(socket);
		Reader consoleReader = new ConsoleReader();
		Reader socketReader = new SocketReader(socket);

		RW serverClient = new RW(socketReader, consoleWriter);
		RW clientServer = new RW(consoleReader, socketWriter);

		ExecutorService pool = Executors.newFixedThreadPool(2);
		Future<Object> serverClientFuture = pool.submit(serverClient);
		Future<Object> clientServerFuture = pool.submit(clientServer);

		try {
			serverClientFuture.get();
			clientServerFuture.get();
		} catch (InterruptedException e) {
			pool.shutdown();
			throw new SilentClientException("some of RW interrupted", e);
		} catch (ExecutionException e) {
			pool.shutdown();
			throw new SilentClientException("ExecutionException", e);
		}

		log.info("client starting finish");
	}

}
